//
// Ephi - simulation of magnetic fields and particles
// Copyright (C) 2007 Indrek Mandre <indrek(at)mare.ee>
// For more information please see http://www.mare.ee/indrek/ephi/
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "statics.hpp"
#include "screen.hpp"
#include "dynamics.hpp"
#include "consts.hpp"

// test for a moving electron in a homogenous bfield
// we test for accuracy of radius and speed (distance)

#define RADIUS 0.5
#define BFIELD -0.0001
#define SPEEDMS 8794100.7448018854
#define TIME_FOR_QUARTER ((PREC_PI * RADIUS * 2 / 4) / SPEEDMS)
#define BAD_ERROR_RANGE_MAGNITUDE (0.01*0.01)

int main (int argc, char *argv[])
{
  Screen *screen = 0;
  for ( int i = 1; i < argc; i++ )
    {
      if ( !strcmp (argv[i], "-g") && !screen )
        {
          screen = new Screen (800, 800, 4.0, 4.0);
        }
      else
        {
          printf ("%s: %s [-g]\n", argv[0], argv[0]);
          exit(0);
        }
    }

  Statics statics;
  statics.setAmbientBField (vect3d(0, 0, BFIELD));
  ElectroDynamics dyn(statics);
  dyn.setDTM(1, 1);

  vect3d start_pos(0, 0, 0);
  vect3d end_pos(0.5, -0.5, 0);
  vect3d bad_pos(0, -1, 0);

  prec_t speed = ElectroDynamics::ms2eV (SPEEDMS, ELECTRON_MASS);
  dyn.inject_electron (vect3d(0, 0, 0), vect3d(1, 0, 0), speed);
  vect3d original_v = dyn.get_v(0);

  if ( screen )
      screen->draw_axes();

#define PIXEL_INTERVAL 0.0000000001
  prec_t cp = 0;

  while ( true )
    {
      if ( screen && dyn.get_elapsed_time() >= cp )
        {
          screen->set_pixel (dyn.get_pos(0), Screen::RED);
          cp += PIXEL_INTERVAL;
        }

      if ( (dyn.get_pos(0) - bad_pos).magnitude() <= BAD_ERROR_RANGE_MAGNITUDE )
        {
          printf ("ERROR: Electron did half a circle already, something must be way off\n");
          break;
        }

      if ( dyn.get_elapsed_time() >= TIME_FOR_QUARTER )
        {
          if ( (dyn.get_pos(0) -  end_pos).magnitude() > BAD_ERROR_RANGE_MAGNITUDE )
              printf ("ERROR: completed time but electron is not where it is supposed to be\n");
          else
              printf ("OK: electron found where it's supposed to be :)\n");
          break;
        }
      dyn.step ();
    }

  printf ("TIME=%g\n", prec2double(dyn.get_elapsed_time()));
  char buf[128];
  printf ("POS=%s\n", dyn.get_pos(0).sprint(buf));
  printf ("V=%s\n", dyn.get_v(0).sprint(buf));
  printf ("POS_MARGIN=%g\n", prec2double((dyn.get_pos(0) -  end_pos).length()));
  prec_t v_margin = fabs(dyn.get_v(0).length() -  original_v.length());
  printf ("V_MARGIN=%g (%g%%)\n", prec2double(v_margin), prec2double (100.0 * v_margin / original_v.length()));

  if ( screen )
    {
      screen->write ("test1.bmp");
      delete screen;
    }

  return 0;
}

